package com.fizz.redpacket.lock;

import com.fizz.redpacket.lock.RedisLock;
/*     */ import com.fizz.redpacket.lock.RejectPolicy;
/*     */ import com.fizz.redpacket.lock.RejectPolicyFactory;
/*     */ import java.util.UUID;
/*     */ import java.util.concurrent.TimeUnit;
/*     */ import org.springframework.data.redis.core.RedisTemplate;
/*     */ import org.springframework.data.redis.core.ValueOperations;

public class RedisSycRedisLock extends RedisLock {
    private RedisSycRedisLock() {}

    public RedisSycRedisLock(RedisTemplate<String, Object> template, RejectPolicyFactory factory, long expired) {
        super(template, factory, expired);
    }

    public RedisSycRedisLock(RedisTemplate<String, Object> template, long expired) {
        super(template, expired);
    }


    ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public void lock() {
        String lockKey = "@@@lock@@@";
        long expireTime = this.expired;
        String value = UUID.randomUUID().toString();
        this.threadLocal.set(value);
        ValueOperations<String, Object> operations = this.template.opsForValue();
        boolean lockSucceed = operations.setIfAbsent(lockKey, value, expireTime, TimeUnit.SECONDS).booleanValue();
        if (lockSucceed) {
            return;
        }

        this.rejectPolicyFactory.getRejectPolicy();
    }

    public boolean tryLock() {
        String lockKey = "@@@lock@@@";
        long expireTime = this.expired;
        String value = UUID.randomUUID().toString();
        this.threadLocal.set(value);
        ValueOperations<String, Object> operations = this.template.opsForValue();
        return operations.setIfAbsent(lockKey, value, expireTime, TimeUnit.SECONDS).booleanValue();
    }

public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        String lockKey = "@@@lock@@@";
        long expireTime = this.expired;
        String value = UUID.randomUUID().toString();
        this.threadLocal.set(value);
        ValueOperations<String, Object> operations = this.template.opsForValue();
        boolean isLock = operations.setIfAbsent(lockKey, value, expireTime, TimeUnit.SECONDS).booleanValue();
        if (isLock) {
            return true;
        }
        long start = System.currentTimeMillis();
        do {

        } while (!operations.setIfAbsent(lockKey, value, expireTime, TimeUnit.SECONDS).booleanValue() &&
        System.currentTimeMillis() - start <= time);

         RejectPolicy policy = this.rejectPolicyFactory.getRejectPolicy();
        policy.reject(this.template);
        return false;
    }

public void unlock() {
    String lockKey = "@@@lock@@@";
    String actualValue = (String)this.template.opsForValue().get(lockKey);
    String expectValue = this.threadLocal.get();
    if (actualValue == null || expectValue == null) {
      return;
    }
    if (actualValue.equals(expectValue)) {
        this.template.delete(lockKey);
   }
   this.threadLocal.remove();
 }
}
